package com.vim.modules.web.controller;

import com.google.common.base.Strings;
import com.vim.common.annotation.ParentModuleInfo;
import com.vim.common.annotation.SysLogRecord;
import com.vim.common.model.response.Response;
import com.vim.common.model.response.RestfulResponse;
import com.vim.common.utils.ValidateUtils;
import com.vim.common.utils.HostNameProvider;
import com.vim.modules.web.model.ModuleInfo;
import com.vim.modules.web.service.ModuleInfoService;
import com.vim.modules.web.service.SysMenuService;
import io.swagger.annotations.Api;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import io.swagger.models.Tag;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponents;
import springfox.documentation.service.Documentation;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

@RestController
@RequestMapping("/moduleInfo")
public class ModuleInfoController {

    private final String hostNameOverride;
    private final DocumentationCache documentationCache;
    private final ServiceModelToSwagger2Mapper mapper;
    private final JsonSerializer jsonSerializer;

	@Resource
	private ModuleInfoService moduleInfoService;

	@Resource
	private SysMenuService sysMenuService;

    @Autowired
    public ModuleInfoController(Environment environment, DocumentationCache documentationCache, ServiceModelToSwagger2Mapper mapper, JsonSerializer jsonSerializer) {
        this.hostNameOverride = environment.getProperty("springfox.documentation.swagger.v2.host", "DEFAULT");
        this.documentationCache = documentationCache;
        this.mapper = mapper;
        this.jsonSerializer = jsonSerializer;
    }

    /**
     * 初始化所有模块
     */
    @SysLogRecord
    @RequestMapping("/initModuleList")
    public RestfulResponse initModuleList(){
        List<ModuleInfo> moduleList = new ArrayList<>();
        Map<String, String> parentModule = new HashMap<>();

        Reflections reflections = new Reflections("com.vim.modules.web.api");
        Set<Class<?>> classesList = reflections.getTypesAnnotatedWith(ParentModuleInfo.class);
        for (Class moduleClass : classesList) {
            ParentModuleInfo info = (ParentModuleInfo) moduleClass.getAnnotation(ParentModuleInfo.class);
            Api api = (Api)moduleClass.getAnnotation(Api.class);
            if(parentModule.get(info.moduleCode()) == null){
                parentModule.put(info.moduleCode(), info.moduleName());
            }
            ModuleInfo moduleInfo = new ModuleInfo();
            moduleInfo.setModuleCode(moduleClass.getSimpleName());
            moduleInfo.setModuleName(api.value());
            moduleInfo.setModuleDesc(api.description());
            moduleInfo.setModuleParentCode(info.moduleCode());
            moduleInfo.setModuleParentName(info.moduleName());
            moduleList.add(moduleInfo);
        }

        moduleInfoService.initModuleList(moduleList);
        return new RestfulResponse(Response.OK);
    }

    /**
     * 所有父级模块
     */
    @RequestMapping("/moduleOneLevelList")
    public RestfulResponse moduleOneLevelList(){
        List<ModuleInfo> list = moduleInfoService.findOneLevelList();
        return new RestfulResponse(list);
    }

    /**
     * 子模块
     */
    @RequestMapping("/moduleSubLevelList")
    public RestfulResponse moduleSubLevelList(@RequestParam(value = "moduleCode") String moduleCode){
        ValidateUtils.checkNotBlank(moduleCode);
        List<ModuleInfo> list = moduleInfoService.findSubLevelList(moduleCode);
        return new RestfulResponse(list);
    }

    /**
     * 模块文档
     */
    @RequestMapping("/moduleDocument")
    public ResponseEntity<Json> moduleDocument(@RequestParam(value = "moduleCode") String moduleCode, HttpServletRequest servletRequest){
        ValidateUtils.checkNotBlank(moduleCode);
        moduleCode = upperToUnderline(moduleCode);
        Documentation documentation = this.documentationCache.documentationByGroup("default");
        if (documentation == null) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        } else {
            Swagger swagger = this.mapper.mapDocumentation(documentation);
            UriComponents uriComponents = HostNameProvider.componentsFrom(servletRequest, swagger.getBasePath());
            swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath());
            if (Strings.isNullOrEmpty(swagger.getHost())) {
                swagger.host(this.hostName(uriComponents));
            }

            List<Tag> tags = swagger.getTags();
            Iterator<Tag> it = tags.iterator();
            while(it.hasNext()){
                Tag tag = it.next();
                if(!tag.getName().equals(moduleCode)){
                    it.remove();
                }
            }

            Map<String, Path> pathMap = swagger.getPaths();
            List<String> existList = new ArrayList<>();
            for(String str:pathMap.keySet()){
                Path path = pathMap.get(str);
                List<String> tagList = new ArrayList<>();
                if(null == path.getGet()){
                    tagList = path.getPost().getTags();
                }else{
                    tagList = path.getGet().getTags();
                }
                for(String tagStr:tagList){
                    if(!tagStr.equals(moduleCode)){
                        existList.add(str);
                    }
                }
            }
            for(String str:existList){
                pathMap.remove(str);
            }

            return new ResponseEntity(this.jsonSerializer.toJson(swagger), HttpStatus.OK);
        }
    }

    private String hostName(UriComponents uriComponents) {
        if ("DEFAULT".equals(this.hostNameOverride)) {
            String host = uriComponents.getHost();
            int port = uriComponents.getPort();
            return port > -1 ? String.format("%s:%d", host, port) : host;
        } else {
            return this.hostNameOverride;
        }
    }

    private String upperToUnderline(String str){
        String ss = "";
        char[] charArray = str.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            if(charArray[i] >= 'A' && charArray[i] <= 'Z'){
                if(i == 0){
                    ss += Character.toLowerCase(charArray[i]);
                }else{
                    ss += "-"+Character.toLowerCase(charArray[i]);
                }
            }else{
                ss += charArray[i];
            }
        }
        return ss;
    }
}

